#include<iostream>
#include<vector>
#include<cstdio>
#include<semaphore.h>
#include<pthread.h>

#define MaxQueue 5
template <class T>
class RingQueue{
  private:
    std::vector<T>_arr;
    int _capacity;
    sem_t _sem_idle;
    sem_t _sem_data;
    sem_t _sem_lock;
    int read_step;
    int write_step;
  public:
    RingQueue(int capacity=MaxQueue)
      :_capacity(capacity),_arr(capacity),read_step(0),write_step(0)
    {
      sem_init(&_sem_idle,0,capacity);
      sem_init(&_sem_data,0,0);
      sem_init(&_sem_lock,0,1);
    }
    bool Push(const T&data)
    {
      //先判断，后加锁
      sem_wait(&_sem_idle);
      sem_wait(&_sem_lock);
      //放数据
      _arr[write_step]=data;
      write_step=(write_step+1)%_capacity;
      //进行V操作，释放资源
      sem_post(&_sem_lock);
      sem_post(&_sem_data);
      return true;
    }
    bool Pop(T* data)
    {
      sem_wait(&_sem_data);
      sem_wait(&_sem_lock);
      //取数据
      *data=_arr[read_step];
      read_step=(read_step+1)%_capacity;
      sem_post(&_sem_lock);
      sem_post(&_sem_idle);
    }
    ~RingQueue()
    {
      sem_destroy(&_sem_idle);
      sem_destroy(&_sem_data);
      sem_destroy(&_sem_lock);
    }
};

#define Max_USER 4
void* productor(void* arg)
{
  RingQueue<int>* q=(RingQueue<int>*)arg;
  int data=0;
  while(1)
  {
    q->Push(data);
    printf("++++++ %p thread push data:%d\n",pthread_self(),data++);
  }
  return NULL;
}
void* consumer(void* arg)
{
  RingQueue<int>* q=(RingQueue<int>*)arg;
  while(1)
  {
    int data;
    q->Pop(&data);
    printf("------ %p thread pop data:%d\n",pthread_self(),data);
  }
  return NULL;
}
int main()
{
  RingQueue<int> q;
  pthread_t con_tid[Max_USER],pro_tid[Max_USER];
  int ret;
  for(int i=0;i<Max_USER;++i)
  {
    pthread_create(&pro_tid[i],NULL,productor,(void*)&q);
    if(ret!=0)
    {
      std::cout<<"pthread_create error\n";
      return -1;
    }

    pthread_create(&con_tid[i],NULL,consumer,(void*)&q);
    if(ret!=0)
    {
      printf("pthread_create error\n");
      return -1;
    }
  }

  for(int i=0;i<Max_USER;++i)
  {
    pthread_join(con_tid[i],NULL);
    pthread_join(pro_tid[i],NULL);
  }
  return 0;
}
